# -*- coding: utf-8 -*-
""" Projection Dialog: a widget to choose Datum / Projection from pyproj

    :Author:
      - 20111221-20120313 Roberto Vidmar

    :Revision:  $Revision: 52 $
                $Date: 2012-11-12 09:07:15 +0000 (Mon, 12 Nov 2012) $

    :Copyright: 2011-2012
                Nicola Creati <ncreati@inogs.it>
                Roberto Vidmar <rvidmar@inogs.it>

    :License: MIT/X11 License (see :download:`license.txt
                               <../../license.txt>`)
"""

import sys
from qtCompat import Qt, QtCore, QtGui
QCA = QtCore.QCoreApplication

from projMVC import (ProjView, ProjModel, SaveEPSGDialog, DATUMSHIFT_KEYWORD,
  GEOIDGRIDS_KEYWORD, EXTRA_KEYWORDS)

#===============================================================================
class SearchWidget(QtGui.QWidget):
  """ Search for a string in the projection tree.
      The widget has a button and a QlineEdit field.
  """
  def __init__(self, parent, text=''):
    """ Create a new SearchWidget instance.

      :param parent: parent widget
      :type parent: QtGui widget
      :param text: the text to search for
      :type text: string
      :raises:
    """
    super(SearchWidget, self).__init__(parent)

    self.searchEditor = QtGui.QLineEdit(text, self)
    self.searchEditor.setToolTip(QCA.translate("SearchWidget",
      "Enter here the string to search for.\n"
      "This string will be searched through\nall known coordinate reference "
      "system"))
    self.defaultText = QCA.translate("SearchWidget", 'New Search:')
    self.searchBtn = QtGui.QPushButton(self.defaultText, self)
    self.searchBtn.setToolTip(
      QCA.translate("SearchWidget",
      "Click here to search for the string to the right\n"
      "among all known coordinate reference system"))
    self.defaultText = QCA.translate("SearchWidget", 'New Search:')
    self.searchBtn.setIcon(QtGui.QIcon(":/icon_search.png"))

    o = QtGui.QHBoxLayout()
    o.addWidget(self.searchBtn)
    o.addWidget(self.searchEditor)

    self.setLayout(o)

    # Connect button to search method
    self.searchBtn.clicked.connect(self.parent().search)
    self.searchEditor.textChanged.connect(self.onTextChanged)

  def onTextChanged(self):
    """ Update text contained in the search button
    """
    self.searchBtn.setText(self.defaultText)

  def text(self):
    """ Return text contained in the QLineEdit widget

      :returns: text contained in the QLineEdit widget
      :rtype: string
      :raises:
    """
    return self.searchEditor.text()

  def setText(self, text):
    """ Set the text contained in the QLineEdit widget

      :param text: new text
      :type text: string
      :raises:
    """
    self.searchEditor.setText(text)

  def resetBtnText(self):
    """ Reset the text contained in the Button widget to its default
    """
    self.searchBtn.setText(self.defaultText)

  def setBtnText(self, text):
    """ Set the text contained in the Button widget to text

      :param text: new text
      :type text: string
      :raises:
    """
    self.searchBtn.setText(text)

#===============================================================================
class ProjDialog(QtGui.QDialog):
  """ Projection selection dialog
  """
  WGS84 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
  def __init__(self, proj=WGS84, parent=None):
    """ Create a new ProjDialog instance.

      :param proj: the PROJ.4 string defining the projection
      :type proj: string
      :param parent: parent widget
      :type parent: QtGui widget
      :raises:
    """
    super(ProjDialog, self).__init__(parent)

    self.setWindowTitle(QCA.translate("ProjDialog", "Datum and Projections"))
    self.foundProjStr = None

    # Projections Tree
    self.tree = ProjView(self)
    # Set the tree model
    model = ProjModel()
    model.load()
    self.tree.setModel(model)
    self.tree.selectionModel().currentChanged.connect(self.onCurrentChanged)
    self.tree.setColumnHidden(2, True)
    self.tree.resizeView()

    # Current Projection
    currentProj = QtGui.QHBoxLayout()
    self.currentProjLabel = QtGui.QLabel(proj)
    self.currentProjLabel.setToolTip(
      QCA.translate("ProjDialog", "The current Datum/Projection PROJ.4 string"))
    self.currentProjLabel.setTextInteractionFlags(Qt.TextBrowserInteraction)

    f = self.currentProjLabel.font()
    f.setBold(True)
    self.currentProjLabel.setFont(f)
    self.currentProjLabel.setWordWrap(True)
    self.currentProjLabel.setAlignment(Qt.AlignLeft)
    currentLabel = QtGui.QLabel(QCA.translate("ProjDialog",
      "Current Projection:  "))
    currentLabel.setToolTip(QCA.translate("ProjDialog",
      "The Datum/Projection in use now"))
    currentProj.addWidget(currentLabel, alignment=Qt.AlignTop)
    currentProj.addWidget(self.currentProjLabel, stretch=1,
      alignment=Qt.AlignTop)

    # Search widget
    self.searchWidget = SearchWidget(self, proj)
    searchGroup = QtGui.QGroupBox(
      QCA.translate("ProjDialog",
      "Search for PROJ.4 (sub)string or EPSG code:"))
    searchGroup.setToolTip(QCA.translate("ProjDialog",
      "You can search for any text through all\n"
      "known Coordinate Reference Systems\nand EPSG codes"))
    searchGroup.setStyleSheet(" background-color: qlineargradient("
      "x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E0E0E0, stop: 1 #FFFFFF); ")

    v = QtGui.QVBoxLayout()
    v.addWidget(self.searchWidget)
    searchGroup.setLayout(v)

    # Dialog standard buttons
    self.buttonBox = QtGui.QDialogButtonBox(self)
    self.buttonBox.setOrientation(Qt.Horizontal)
    self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|
      QtGui.QDialogButtonBox.Ok)

    # Layout                
    layout = QtGui.QVBoxLayout()
    layout.addLayout(currentProj)
    layout.addWidget(self.tree)
    #layout.addWidget(self.searchWidget)
    layout.addWidget(searchGroup)
    layout.addWidget(self.buttonBox)
    self.setLayout(layout)

    # SIGNAL
    self.tree.clicked.connect(self.onCurrentChanged)
    self.buttonBox.accepted.connect(self.accept)
    self.buttonBox.rejected.connect(self.reject)

    # Start search as if button was pressed
    if self.search(exact=True):
      # Found! Clear search field and button
      self.searchWidget.resetBtnText()
    else:
      dlg = SaveEPSGDialog(proj, '')
      if dlg.exec_():
        customProjStr, epsgString = dlg.text()
        newIndex = model.addCustom(customProjStr, epsgString)
        self.tree.customAdded(newIndex)
    self.searchWidget.setText('')

  def keyPressEvent(self, event):
    """ Reimplementation of keyPressEvent to disable default behaviour
        of Return key (i.e. trigger the Ok button).
    """
    if event.key() == Qt.Key_Escape:
      self.reject()
    elif event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
      self.search()
    else:
      super(ProjDialog, self).keyPressEvent(event)

  def updateCurrent(self, text):
    """ Update current projection string

      :param text: new text
      :type text: string
      :raises:
    """
    self.currentProjLabel.setText(text)

  def onCurrentChanged(self, curIdx=None, preIdx=None):
    item = self.tree.currentIndex().internalPointer()
    if item.isBranch():
      self.updateCurrent('')
    else:
      self.updateCurrent(item.projStr())

  def search(self, exact=False):
    """ Search projection string in tree

      :param exact: if False search also substrings
      :type exact: bool
      :raises:
    """
    # Get the projection from the editor
    projStr = self.searchWidget.text()

    if projStr == '':
      # We don't search anything
      self.searchWidget.resetBtnText()
      self.tree.clearSelection()
      self.tree.collapseAll()
      return
    else:
      if projStr != self.foundProjStr:
        # New Search
        self.foundList = []
        # Reset text
        self.searchWidget.resetBtnText()
        self.foundList = self.tree.model().search(
          str(projStr), matchCase=False, exact=exact)
        if len(self.foundList) > 0:
          # found!
          self.foundProjStr = projStr
          self.foundIndex = 0
      else:
        self.foundIndex += 1
        if self.foundIndex == len(self.foundList):
          self.foundIndex = 0

      if self.foundList:
        howmany = len(self.foundList)
        if howmany == 1:
          msg = QCA.translate("ProjDialog", "1 of 1")
        else:
          msg = (QCA.translate("ProjDialog", "Move to %s of %s") %
            ((self.foundIndex + 1) % howmany + 1,
            howmany))
        self.searchWidget.setBtnText(msg)
        idx = self.foundList[self.foundIndex]
        self.tree.setCurrentIndex(self.tree.model().indexOfCol0(idx))
        self.tree.resizeView()
        return True
      else:
        return False

  def projection(self):
    """ Return current projection string

      :returns: current projection string
      :rtype: string
      :raises:
    """
    return str(self.currentProjLabel.text())

  def _showSelection(self, index):
    """ Show selected item proj4 string

      :param index: ???
      :type index: ???
      :raises:
    """
    index = self.tree.currentIndex()
    item = self.tree.model().nodeFromIndex(index)
    if item.isLeaf():
      self.searchWidget.setText(item.projStr())

#===============================================================================
if __name__ == "__main__":

  import signal
  signal.signal(signal.SIGINT, signal.SIG_DFL)

  app = QtGui.QApplication(sys.argv)
  form = ProjDialog()
  form.resize(640, 480)
  if form.exec_():
    print form.projection()
  sys.exit(app.exec_())
